<script setup>
import 'leaflet/dist/leaflet.css'
import '@supermap/iclient-leaflet/css/index'
import 'mapbox-gl/dist/mapbox-gl.css'

import iServerConfigUrl from '/iServerConfig.json?url'

import { ElMessage } from 'element-plus'
import $ from 'jquery'
import axios from 'axios'

import L from 'leaflet'
import '@supermap/iclient-leaflet'
import 'proj4leaflet'
import 'mapbox-gl-leaflet'

import { Edit, Delete, Star } from '@element-plus/icons-vue'
import { inject } from 'vue'

const themeProps = {
    value: "id",
    label: "label",
    children: undefined,
    color: "color"
};
</script>

<template>
    <el-button :icon="Edit" circle class="mvtStyleEditBtn" @click="updateMvtStyleEditCardStatus" />
    <el-card class="MvtStyleCard">
        <template #header>
            <div class="MvtStyleCardHeader">
                <span>矢量样式</span>
            </div>
        </template>
        <span class="fillStyleTitle">面样式</span>
        <span class="fillColor">面填充：</span>
        <el-input class="fillColorInput" v-model="fillColor" placeholder="fill color" />
        <span class="fillColorPicker">
            <el-color-picker v-model="fillColor" show-alpha></el-color-picker>
        </span>
        <span class="circleStyleTitle">点样式</span>
        <span class="circleColor">点颜色：</span>
        <el-input class="circleColorInput" v-model="circleColor" placeholder="circle color" />
        <span class="circleColorPicker">
            <el-color-picker v-model="circleColor" show-alpha></el-color-picker>
        </span>
        <span class="circleRadius">点半径：</span>
        <el-input-number class="circleRadiusInputNumber" v-model="circleRadius" :precision="2" :step="0.1" :min="0.01" />
        <span class="lineStyleTitle">线样式</span>
        <span class="lineColor">线颜色：</span>
        <el-input class="lineColorInput" v-model="lineColor" placeholder="line color" />
        <span class="lineColorPicker">
            <el-color-picker v-model="lineColor" show-alpha></el-color-picker>
        </span>
        <span class="lineWidth">线宽：</span>
        <el-input-number class="lineWidthInputNumber" v-model="lineWidth" :precision="2" :step="0.1" :min="0.01" />
        <el-button class="button" :icon="Edit" round @click="handleAppliedBtnClicked">应用</el-button>
        <el-button class="button" :icon="Delete" round @click="handleResetBtnClicked">复位</el-button>
        <el-button class="button" :icon="Star" round @click="handleCreateThemeLayerBtnClicked">专题图</el-button>
    </el-card>
    <el-tree-v2 class="themeTree" :data="themeData" :default-checked-keys="themeCheckedKeys" :props="themeProps" show-checkbox :height="182"
        @check="handleThemeItemClicked">
        <template #default="{ node }">
            <span class="prefix" :class="{ 'is-leaf': node.isLeaf }">
                <div :style="{ 'background-color': node.data.color, width: '72px', height: '24px', 'border-radius': '4px' }"></div>
            </span>
            <span :style="{ 'line-height': '24px' }">{{ node.label }}</span>
        </template>
    </el-tree-v2>
</template>

<script>
export default {
    name: 'VectorTile',
    data() {
        return {
            mvtServiceUrl: undefined,
            mvtLayer: {},
            mvtDefaultStyle: undefined,
            highlightKey: 'highlight',
            highlightFillPaint: {
                'fill-color': 'rgba(255,0,0,1)',
                'fill-opacity': 0.3
            },
            highlightLinePaint: {
                'line-color': 'rgba(255,0,0,1)',
                'line-opacity': 0.3,
                'line-width': 4
            },
            highlightCirclePaint: {
                'circle-color': 'rgba(255,0,0,1)',
                'circle-opacity': 0.3,
                'circle-radius': 6
            },
            popup: undefined,
            fillColor: 'rgba(151, 191, 242, 1)',
            circleColor: 'rgba(54, 96, 146, 1)',
            circleRadius: 3.78,
            lineColor: 'rgba(102, 102, 102, 1)',
            lineWidth: 0.38,
            themeLayerKey: 'themeLayer',
            themeData: [],
            themeCheckedKeys: []
        }
    },
    mounted() {
        var map = inject('map');

        axios.get(iServerConfigUrl).then(res => {
            var iServerConfig = res.data;
            this.mvtServiceUrl = `${iServerConfig.urls.VectorTile.protocol}://${iServerConfig.urls.VectorTile.hostname}:${iServerConfig.urls.VectorTile.port}/${iServerConfig.urls.VectorTile.mvtServiceUrl}`;

            // 还原 map 显示范围
            if (map._size.x !== document.body.clientWidth) {
                $("#map")[0].style.width = '';
                map._size.x = document.body.clientWidth;
            }

            map.options.crs = L.CRS.EPSG3857;
            map.options.maxZoom = 8;
            map.options.minZoom = 2;
            map.flyTo([0, 0], 2);

            // 加载 mvt 矢量瓦片地图
            axios.get(this.mvtServiceUrl).then(res => {
                this.mvtLayer = new L.mapboxGL({
                    renderWorldCopies: false,
                    style: res.data,
                    crs: L.CRS.EPSG3857,
                    minZoom: 0,
                    maxZoom: 8
                }).addTo(map);

                // 获取 mvt 默认样式
                this.mvtDefaultStyle = res.data;

                // 实现 mvt 矢量瓦片地图点击高亮效果
                var mapboxglMap = this.mvtLayer.getMapboxMap();
                map.on('click', e => {
                    var highlightLayer = mapboxglMap.getLayer(this.highlightKey);
                    if (highlightLayer !== undefined) {
                        mapboxglMap.removeLayer(this.highlightKey);
                        highlightLayer = undefined;
                    }

                    var features = mapboxglMap.queryRenderedFeatures([e.originalEvent.offsetX, e.originalEvent.offsetY]);
                    if (features.length > 0) {
                        // 高亮第一个选中对象
                        var feature = features[0];
                        var highlightLayer = mapboxglMap.addLayer({
                            'id': this.highlightKey,
                            'type': feature.layer.type,
                            'filter': ['in', '$id', feature.id],
                            'source': feature.source,
                            'source-layer': feature.sourceLayer,
                            'paint': feature.layer.type === 'fill' ?
                                this.highlightFillPaint :
                                feature.layer.type === 'line' ?
                                    this.highlightLinePaint :
                                    this.highlightCirclePaint
                        });

                        // 显示高亮数据的属性信息
                        var props = '';
                        var properties = feature.properties;
                        if (properties !== undefined) {
                            for (let key in properties) {
                                var value = properties[key];
                                if (value.toString().length > 0) {
                                    props += `${key}: ${properties[key]}<br />`;
                                }
                            }
                            if (props.length === 0) {
                                props = '属性为空';
                            }
                        }
                        this.popup = new L.popup().setLatLng(e.latlng).setContent(`<p>${props}</p>`);
                        this.popup.openOn(map)
                    }
                });
            }).catch(err => {
                console.log(err);
            });
        }).catch(err => {
            ElMessage.error(err.stack);
        });
    },
    methods: {
        // 更新 mvt 样式控制面板状态
        updateMvtStyleEditCardStatus() {
            var mvtStyleCard = $(".MvtStyleCard")[0];
            if (mvtStyleCard.style.display !== 'none') {
                mvtStyleCard.style.display = 'none';
            } else {
                mvtStyleCard.style.display = 'block';
            }
        },

        // 矢量数据样式应用
        handleAppliedBtnClicked() {
            if (this.mvtLayer !== undefined) {
                var mapboxglMap = this.mvtLayer.getMapboxMap();
                var themeLayer = mapboxglMap.getLayer(this.themeLayerKey);
                if (themeLayer !== undefined) {
                    mapboxglMap.removeLayer(this.themeLayerKey);
                    themeLayer = undefined;
                    var themeTree = $(".themeTree")[0];
                    themeTree.style.display = 'none';
                }
                var style = mapboxglMap.getStyle();
                for (let i = 0; i < style.layers.length; i++) {
                    const styleLayer = style.layers[i];
                    var layerType = styleLayer.type;
                    switch (layerType) {
                        case 'fill':
                            styleLayer.paint['fill-color'] = this.fillColor;
                            break;
                        case 'line':
                            styleLayer.paint['line-color'] = this.lineColor;
                            styleLayer.paint['line-width'] = this.lineWidth;
                            break;
                        case 'circle':
                            styleLayer.paint['circle-color'] = this.circleColor;
                            styleLayer.paint['circle-radius'] = this.circleRadius;
                            break;
                    }
                }
                mapboxglMap.setStyle(style);
            }
        },

        // 矢量数据样式复位
        handleResetBtnClicked() {
            if (this.mvtLayer !== undefined) {
                var mapboxglMap = this.mvtLayer.getMapboxMap();
                var themeLayer = mapboxglMap.getLayer(this.themeLayerKey);
                if (themeLayer !== undefined) {
                    mapboxglMap.removeLayer(this.themeLayerKey);
                    themeLayer = undefined;
                    var themeTree = $(".themeTree")[0];
                    themeTree.style.display = 'none';
                }
                mapboxglMap.setStyle(this.mvtDefaultStyle);
            }
        },

        // 创建专题图
        handleCreateThemeLayerBtnClicked() {
            if (this.mvtLayer !== undefined) {
                var themeTree = $(".themeTree")[0];
                var mapboxglMap = this.mvtLayer.getMapboxMap();
                var themeLayer = mapboxglMap.getLayer(this.themeLayerKey);
                if (themeLayer !== undefined) {
                    mapboxglMap.removeLayer(this.themeLayerKey);
                    themeLayer = undefined;
                    themeTree.style.display = 'none';
                } else {
                    var features = mapboxglMap.queryRenderedFeatures({ layers: ['World_3857@world(0_24)'] });
                    if (features.length > 0) {
                        var feature = features[0];
                        var type = feature.layer.type;
                        var source = feature.source;
                        var sourceLayer = feature.sourceLayer;
                        mapboxglMap.addLayer({
                            'id': this.themeLayerKey,
                            'type': type,
                            'source': source,
                            'source-layer': sourceLayer,
                            'paint': {
                                'fill-color': {
                                    property: 'POP_1994',
                                    stops: [
                                        [0, '#ceb9dc'],
                                        [20000000, '#b89dc7'],
                                        [30000000, '#a180b1'],
                                        [40000000, '#8a649b'],
                                        [50000000, '#804f94'],
                                        [60000000, '#76378e'],
                                        [70000000, '#652f79']
                                    ]
                                }
                            }
                        });

                        this.themeData = [
                            {
                                id: 0,
                                label: 'Min ~ 20000000',
                                children: undefined,
                                color: '#ceb9dc'
                            },
                            {
                                id: 1,
                                label: '20000000 ~ 30000000',
                                children: undefined,
                                color: '#b89dc7'
                            },
                            {
                                id: 2,
                                label: '30000000 ~ 40000000',
                                children: undefined,
                                color: '#a180b1'
                            },
                            {
                                id: 3,
                                label: '40000000 ~ 50000000',
                                children: undefined,
                                color: '#8a649b'
                            },
                            {
                                id: 4,
                                label: '50000000 ~ 60000000',
                                children: undefined,
                                color: '#804f94'
                            },
                            {
                                id: 5,
                                label: '60000000 ~ 70000000',
                                children: undefined,
                                color: '#76378e'
                            },
                            {
                                id: 6,
                                label: '70000000 ~ Max',
                                children: undefined,
                                color: '#652f79'
                            }
                        ];

                        this.themeCheckedKeys = [0, 1, 2, 3, 4, 5, 6];

                        themeTree.style.display = 'block';
                    }
                }
            }
        },

        // 专题图图层过滤
        handleThemeItemClicked(data, info) {
            var themeFilter = ['in', 'POP_1994'];
            var mapboxglMap = this.mvtLayer.getMapboxMap();
            var features = mapboxglMap.queryRenderedFeatures({ layers: ['World_3857@world(0_24)'] });
            var checkedKeys = info.checkedKeys;
            if (checkedKeys !== undefined && checkedKeys.length > 0) {
                for (let i = 0; i < checkedKeys.length; i++) {
                    const checkedKey = checkedKeys[i];
                    switch (checkedKey) {
                        case 0:
                            for (let i = 0; i < features.length; i++) {
                                const pop = features[i].properties.POP_1994;
                                if (pop < 20000000) {
                                    themeFilter[themeFilter.length] = pop;
                                }
                            }
                            break;
                        case 1:
                            for (let i = 0; i < features.length; i++) {
                                const pop = features[i].properties.POP_1994;
                                if (pop >= 20000000 && pop < 30000000) {
                                    themeFilter[themeFilter.length] = pop;
                                }
                            }
                            break;
                        case 2:
                            for (let i = 0; i < features.length; i++) {
                                const pop = features[i].properties.POP_1994;
                                if (pop >= 30000000 && pop < 40000000) {
                                    themeFilter[themeFilter.length] = pop;
                                }
                            }
                            break;
                        case 3:
                            for (let i = 0; i < features.length; i++) {
                                const pop = features[i].properties.POP_1994;
                                if (pop >= 40000000 && pop < 50000000) {
                                    themeFilter[themeFilter.length] = pop;
                                }
                            }
                            break;
                        case 4:
                            for (let i = 0; i < features.length; i++) {
                                const pop = features[i].properties.POP_1994;
                                if (pop >= 50000000 && pop < 60000000) {
                                    themeFilter[themeFilter.length] = pop;
                                }
                            }
                            break;
                        case 5:
                            for (let i = 0; i < features.length; i++) {
                                const pop = features[i].properties.POP_1994;
                                if (pop >= 60000000 && pop < 70000000) {
                                    themeFilter[themeFilter.length] = pop;
                                }
                            }
                            break;
                        case 6:
                            for (let i = 0; i < features.length; i++) {
                                const pop = features[i].properties.POP_1994;
                                if (pop >= 70000000) {
                                    themeFilter[themeFilter.length] = pop;
                                }
                            }
                            break;
                    }
                }
            }

            mapboxglMap.setFilter(this.themeLayerKey, themeFilter);
        }
    }
}
</script>

<style scoped>
.mvtStyleEditBtn {
    top: 90px;
    right: 30px;
    z-index: 1000;
    position: absolute;
    background-color: rgba(240, 255, 255, 0.7);
}

.MvtStyleCard {
    position: absolute;
    width: 360px;
    height: 520px;
    z-index: 999;
    background-color: rgba(240, 255, 255, 0.7);
    right: 0px;
    margin: 20px;
    border-radius: 20px;
    line-height: 750px;
}

.MvtStyleCardHeader {
    line-height: 32px;
    font-weight: 600;
    font-size: 24px;
}

.fillStyleTitle {
    font-weight: 600;
    font-size: 18px;
    position: absolute;
    left: 26px;
    line-height: 32px;
}

.fillColor {
    font-size: 16px;
    position: absolute;
    left: 36px;
    line-height: 32px;
    top: 130px;
}

.fillColorInput {
    position: absolute;
    top: 130px;
    left: 110px;
    width: calc(100% - 180px);
}

.fillColorPicker {
    position: absolute;
    top: 130px;
    right: 36px;
    line-height: 32px;
}

.circleStyleTitle {
    font-weight: 600;
    font-size: 18px;
    position: absolute;
    left: 26px;
    line-height: 32px;
    top: 180px;
}

.circleColor {
    font-size: 16px;
    position: absolute;
    left: 36px;
    line-height: 32px;
    top: 220px;
}

.circleColorInput {
    position: absolute;
    top: 220px;
    left: 110px;
    width: calc(100% - 180px);
}

.circleColorPicker {
    position: absolute;
    top: 220px;
    right: 36px;
    line-height: 32px;
}

.circleRadius {
    font-size: 16px;
    position: absolute;
    left: 36px;
    line-height: 32px;
    top: 260px;
}

.circleRadiusInputNumber {
    font-size: 16px;
    position: absolute;
    right: 36px;
    line-height: 32px;
    top: 260px;
    width: calc(100% - 146px);
}

.lineStyleTitle {
    font-weight: 600;
    font-size: 18px;
    position: absolute;
    left: 26px;
    line-height: 32px;
    top: 310px;
}

.lineColor {
    font-size: 16px;
    position: absolute;
    left: 36px;
    line-height: 32px;
    top: 350px;
}

.lineColorInput {
    position: absolute;
    top: 350px;
    left: 110px;
    width: calc(100% - 180px);
}

.lineColorPicker {
    position: absolute;
    top: 350px;
    right: 36px;
    line-height: 32px;
}

.lineWidth {
    font-size: 16px;
    position: absolute;
    left: 36px;
    line-height: 32px;
    top: 390px;
}

.lineWidthInputNumber {
    font-size: 16px;
    position: absolute;
    right: 36px;
    line-height: 32px;
    top: 390px;
    width: calc(100% - 146px);
}

.button {
    font-size: 16px;
    font-weight: 600;
}

.themeTree {
    overflow: auto;
    position: absolute;
    width: 360px;
    height: 182px;
    z-index: 999;
    background-color: rgba(240, 255, 255, 0.7);
    right: 0px;
    top: 600px;
    margin: 20px;
    display: none;
}

.prefix {
    margin-right: 10px;
    width: 72px;
    line-height: 24px;
}
</style>